#include "LogicAdd.h"

string LogicAdd::addFloatingTask(Parser::PARSED_COMMAND parsedCommand, vector<Task>& tasksVector, Data* _data, Writer* _writer) {
	
	string statusMessage;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool clash;
	int currentTaskID;
	ErrorAdd dateFormat;
	stringstream repeatCount;

	// empty UI's display
	//tasksVector.clear();
	
	if( tasksVector.empty() )
		_data->getAll(tasksVector);
	// set _task attributes
	string taskName = parsedCommand.addTaskName;
	ptime startTime = parsedCommand.addStartTime;
	ptime endTime = parsedCommand.addEndTime;

	// check if time correct format
	dateFormat = isDateCorrectFormat(startTime, endTime);
	if( dateFormat == ERROR_START_END ) {
		//logErrors(ADD_DATE_START_END_ERROR_MESSAGE, _undoState);
		throw(ADD_DATE_START_END_ERROR_MESSAGE);
	} else if( dateFormat == ERROR_DATE_PAST ) {
		//logErrors(ADD_DATE_PAST_ERROR_MESSAGE, _undoState);
		throw(ADD_DATE_PAST_ERROR_MESSAGE);
	}

	// task creation
	_task = Task(taskName, 0, Task::FLOATING, false, false, startTime, endTime);

	clash = isDateClash(parsedCommand, tasksVector, _data);

	// add into internal data
	dataFeedback = _data->executeAdd(_task);

	// update UI's display
	currentTaskID = _data->getCurrentTaskID();
	_task.setTaskID(currentTaskID);
	tasksVector.push_back(_task);
	
	// ok for clashes
	// inform user of clash via tasksVector (display)
	// return status message to UI
	if( dataFeedback == Data::SUCCESS ) {
		tasks.clear();
		_data->getAll(tasks);
		_writer->write(tasks);
		if( !clash ) {
			statusMessage = ADD_SUCCESS_MESSAGE;
		} else {
			statusMessage = ADD_ERROR_CLASH_MESSAGE;
		}
	} else {
		statusMessage = ADD_ERROR_MESSAGE;
		//logErrors(statusMessage, _undoState);
	}
	
	return statusMessage;
}

string LogicAdd::addDeadlineTask(Parser::PARSED_COMMAND parsedCommand, vector<Task>& tasksVector, Data* _data, Writer* _writer) {
	
	string statusMessage;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool clash;
	int currentTaskID;
	ErrorAdd dateFormat;

	// empty UI's display
	//tasksVector.clear();
	
	if( tasksVector.empty() )
		_data->getAll(tasksVector);
	// set _task attributes
	string taskName = parsedCommand.addTaskName;
	ptime startTime = parsedCommand.addStartTime;
	ptime endTime = parsedCommand.addEndTime;

	// check if time correct format
	dateFormat = isDateCorrectFormat(startTime, endTime);
	if( dateFormat == ERROR_START_END ) {
		//logErrors(ADD_DATE_START_END_ERROR_MESSAGE, _undoState);
		throw(ADD_DATE_START_END_ERROR_MESSAGE);
	} else if( dateFormat == ERROR_DATE_PAST ) {
		//logErrors(ADD_DATE_PAST_ERROR_MESSAGE, _undoState);
		throw(ADD_DATE_PAST_ERROR_MESSAGE);
	}

	// task creation
	_task = Task(taskName, 0, Task::DEADLINE, false, false, startTime, endTime);

	clash = isDateClash(parsedCommand, tasksVector, _data);

	// add to internal data
	dataFeedback = _data->executeAdd(_task);

	// update UI's display
	currentTaskID = _data->getCurrentTaskID();
	_task.setTaskID(currentTaskID);
	tasksVector.push_back(_task);

	// return status message to UI
	if( dataFeedback == Data::SUCCESS ) {
		tasks.clear();
		_data->getAll(tasks);
		_writer->write(tasks);
		
		if( !clash ) {
			statusMessage = ADD_SUCCESS_MESSAGE;
		} else {
			statusMessage = ADD_ERROR_CLASH_MESSAGE;
		}
	} else {
		statusMessage = ADD_ERROR_MESSAGE;
		//logErrors(statusMessage, _undoState);
	}

	return statusMessage;
}

string LogicAdd::addTimedTask(Parser::PARSED_COMMAND parsedCommand, vector<Task>& tasksVector, Data* _data, Writer* _writer) {

	string statusMessage;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool clash;
	int currentTaskID;
	ErrorAdd dateFormat;

	// empty UI's display
	//tasksVector.clear();
	
	if( tasksVector.empty() )
		_data->getAll(tasksVector);
	// set _task attributes
	string taskName = parsedCommand.addTaskName;
	ptime startTime = parsedCommand.addStartTime;
	ptime endTime = parsedCommand.addEndTime;

	// check if time correct format
	dateFormat = isDateCorrectFormat(startTime, endTime);
	if( dateFormat == ERROR_START_END ) {
		//logErrors(ADD_DATE_START_END_ERROR_MESSAGE, _undoState);
		throw(ADD_DATE_START_END_ERROR_MESSAGE);
	} else if( dateFormat == ERROR_DATE_PAST ) {
		//logErrors(ADD_DATE_PAST_ERROR_MESSAGE, _undoState);
		throw(ADD_DATE_PAST_ERROR_MESSAGE);
	}

	// task creation
	_task = Task(taskName, 0, Task::TIMED, false, false, startTime, endTime);

	clash = isDateClash(parsedCommand, tasksVector, _data);

	// add to internal data
	dataFeedback = _data->executeAdd(_task);

	// update UI's display
	currentTaskID = _data->getCurrentTaskID();
	_task.setTaskID(currentTaskID);
	tasksVector.push_back(_task);

	// return status message to UI
	if( dataFeedback == Data::SUCCESS ) {
		tasks.clear();
		_data->getAll(tasks);
		_writer->write(tasks);
		if( !clash ) {
			statusMessage = ADD_SUCCESS_MESSAGE;
		} else {
			statusMessage = ADD_ERROR_CLASH_MESSAGE;
		}
	} else {
		statusMessage = ADD_ERROR_MESSAGE;
		//logErrors(statusMessage, _undoState);
	}

	return statusMessage;
}

// returns a vector containing the tasks that clashed
// either by start|end time
bool LogicAdd::isDateClash(Parser::PARSED_COMMAND parsedCommand, vector<Task>& tasksVector, Data* _data) {

	bool isClash;
	string taskName;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	int oldSize = tasksVector.size();
	int newSize = oldSize;
	taskName = parsedCommand.addTaskName;

	dataFeedback = _data->getAll(tasks);

	for( unsigned int i=0; i<tasks.size(); i++ ) {
		if( tasks[i].getTaskType() != Task::FLOATING ) {
			if( tasks[i].getEndDateTime() > parsedCommand.addStartTime
				&& tasks[i].getStartDateTime() <= parsedCommand.addEndTime ) {
					tasksVector.push_back(tasks[i]);
					newSize = tasksVector.size();
			}
		}
	}

	if( oldSize == newSize ) {
		isClash = false;
	} else {
		isClash = true;
	}

	return isClash;
}

LogicAdd::ErrorAdd LogicAdd::isDateCorrectFormat(ptime startTime, ptime endTime) {
	ErrorAdd dateFormat;

	ptime currTime = second_clock::local_time();
	ptime notADateTime;

	if( currTime > startTime || currTime > endTime ) {
		dateFormat = ERROR_DATE_PAST;
	} else if( startTime > endTime ) {
		if( startTime == notADateTime ) {
			dateFormat = NO_ERROR;
		} else {
			dateFormat = ERROR_START_END;
		}
	} else {
		dateFormat = NO_ERROR;
	}

	return dateFormat;
}

bool LogicAdd::isOutOfBounds(int index, int size) {
	bool outOfBounds;

	if( index <= 0 ) {
		outOfBounds = true;
	} else if( index > size ) {
		outOfBounds = true;
	} else {
		outOfBounds = false;
	}

	return outOfBounds;
}

const string LogicAdd::ADD_SUCCESS_MESSAGE = "Task Added";

const string LogicAdd::ADD_ERROR_MESSAGE = "Unable To Add";
const string LogicAdd::ADD_EXIST_ERROR_MESSAGE = "Task Already Exist";
const string LogicAdd::ADD_ERROR_CLASH_MESSAGE = "Clash";
const string LogicAdd::ADD_DATE_PAST_ERROR_MESSAGE = "Past Date";
const string LogicAdd::ADD_DATE_START_END_ERROR_MESSAGE = "Start Date Earlier";